/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dac.h"
#include "dma.h"
#include "i2c.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "stdlib.h"
#include "control.h"
#include "oled.h"
#include "w25q16.h"
#include "spwm.h"

#include "arm_const_structs.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */


/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
#define DC_VOL_40 0x0630	// Value at UP = 40V, Calibration is required!
#define DC_VOL_50 0x07A0	// Value at UP = 50V, Calibration is required!
#define DC_VOL_55 ((DC_VOL_50+DC_VOL_60)/2)
#define DC_VOL_60 0x08F0	// Value at UP = 60V, Calibration is required!
#define DC_VOL_65 ((DC_VOL_60+DC_VOL_70)/2)
#define DC_VOL_70 0x0A60	// Value at UP = 70V, Calibration is required! Over voltage protect value.

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint8_t FLAG_GLOBAL_OVER_VOLTAGE = 0;
uint8_t FLAG_GLOBAL_OVER_CURRENT = 0;

extern uint16_t adc1_values[adc1_data_num];
extern uint16_t adc1_filter[adc1_channel];
extern float    adc1_average[adc1_channel];

extern uint16_t adc2_values[adc2_data_num];
extern uint16_t adc2_filter[adc2_channel];
extern float    adc2_average[adc2_channel];

int16_t PR1_OUT_R, PR1_OUT_P;
int16_t PI1_OUT_I;

float hspwm_omega = 0;
uint16_t OMEGA = 0;

float rms = 0;
float rms_co = 0;
float rms_temp = 0;
float k_co = 0.40;

float AC_VOL_AVG = 2048.0;	// Calibration is required!
float RMS_SET = 1400000;		// Calibration is required!

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void BSP_Init(void);

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
#ifdef __GNUC__
  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
  return ch;
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2C1_Init();
  MX_TIM1_Init();
  MX_TIM5_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  MX_SPI1_Init();
  MX_ADC2_Init();
  MX_TIM12_Init();
  MX_DAC_Init();
  MX_TIM8_Init();
  MX_TIM9_Init();
  /* USER CODE BEGIN 2 */
	HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc1_values, adc1_data_num);
	HAL_ADC_Start_DMA(&hadc2, (uint32_t *)adc2_values, adc2_data_num);
	HAL_Delay(100);
	
	// controller initial
	PID_Init();
	PR_Init();

	ADC1_Average(adc1_values);
	ADC2_Average(adc2_values);
	
	// close DRV pin
	HAL_GPIO_WritePin(ENABLE1_GPIO_Port, ENABLE1_Pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(ENABLE2_GPIO_Port, ENABLE2_Pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(ENABLE3_GPIO_Port, ENABLE3_Pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(DISABLE1_GPIO_Port, DISABLE1_Pin, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(DISABLE2_GPIO_Port, DISABLE2_Pin, GPIO_PIN_RESET);
	
	// lock the pwm
	HAL_GPIO_WritePin(DRV_GPIO_Port,DRV_Pin,GPIO_PIN_RESET);
	
	// start tim and pwm generate
	HAL_TIM_Base_Start_IT(&htim1);
	HAL_TIM_Base_Start_IT(&htim5);
	HAL_TIM_Base_Start_IT(&htim9);
	HAL_TIM_Base_Start_IT(&htim12);
	
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);					//Start the TIM1 channel1 PWM output with 50kHz
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);					//Start the TIM1 channel2 PWM output with 50kHz
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);					//Start the TIM1 channel3 PWM output with 50kHz
	HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_3);					//Start the TIM8 channel3 PWM output with 50kHz
	
	HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);			//Start the TIM1 channel1_N PWM output
	HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);			//Start the TIM1 channel2_N PWM output
	HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);			//Start the TIM1 channel3_N PWM output
	HAL_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_3);			//Start the TIM3 channel3_N PWM output
	
	__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0);
	__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 0);
	__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, 0);
	__HAL_TIM_SET_COMPARE(&htim8, TIM_CHANNEL_3, 0);
	
	// Set DAC channel1 DHR12RD register
	HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 2048);
	HAL_DAC_SetValue(&hdac, DAC_CHANNEL_2, DAC_ALIGN_12B_R, 2048);
	
	// Enable DAC Channel1
	HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
	
	// start drv and pwm
	HAL_GPIO_WritePin(DRV_GPIO_Port,DRV_Pin,GPIO_PIN_SET);
	HAL_GPIO_WritePin(ENABLE1_GPIO_Port, ENABLE1_Pin, GPIO_PIN_RESET);
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		if(1)
		{
			//printf("AD1 %d %d %d %d\n",adc1_filter[0], adc1_filter[1], adc1_values[2], adc1_values[3]);
			//printf("AD2 %d %d %d %d\n",adc2_filter[0], adc2_filter[1], adc2_values[2], adc2_values[3]);
			HAL_Delay(500);
			HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);		
		}
	}
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage 
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
// Tim count interrupt
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	/* TIM1 50kHz PWM -------------------------------------------------------------- -------------------------------------------------------------- TIM1 50kHz PWM*/
	if(htim->Instance == htim1.Instance)
	{
		static uint16_t adc1_sum_temp1 = 0;
		static uint16_t adc1_sum_temp2 = 0;
		static uint16_t adc1_sum_temp3 = 0;
		
		static int16_t TIM1_SET_COMPARE_CH1 = 0;
		static int16_t TIM1_SET_COMPARE_CH2 = 0;
		static int16_t TIM1_SET_COMPARE_CH3 = 0;
		static int16_t TIM8_SET_COMPARE_CH3 = 0;
		
		/* ADC1 Average */	
		adc1_sum_temp1 += adc1_values[0];
		adc1_sum_temp1 += adc1_values[3];
		adc1_sum_temp1 += adc1_values[6];
		adc1_sum_temp1 += adc1_values[9];
		adc1_sum_temp1 += adc1_values[12];
		adc1_sum_temp1 += adc1_values[15];
		adc1_sum_temp1 += adc1_values[18];
		adc1_sum_temp1 += adc1_values[21];
		adc1_filter[0] =  adc1_sum_temp1 >> 3;
		adc1_sum_temp1 =  0;
		
		adc1_sum_temp2 += adc1_values[1];
		adc1_sum_temp2 += adc1_values[4];
		adc1_sum_temp2 += adc1_values[7];
		adc1_sum_temp2 += adc1_values[10];
		adc1_sum_temp2 += adc1_values[13];
		adc1_sum_temp2 += adc1_values[16];
		adc1_sum_temp2 += adc1_values[19];
		adc1_sum_temp2 += adc1_values[22];
		adc1_filter[1] =  adc1_sum_temp2 >> 3;
		adc1_sum_temp2 =  0;
		
		adc1_sum_temp3 += adc1_values[2];
		adc1_sum_temp3 += adc1_values[5];
		adc1_sum_temp3 += adc1_values[8];
		adc1_sum_temp3 += adc1_values[11];
		adc1_sum_temp3 += adc1_values[14];
		adc1_sum_temp3 += adc1_values[17];
		adc1_sum_temp3 += adc1_values[20];
		adc1_sum_temp3 += adc1_values[23];
		adc1_filter[2] =  adc1_sum_temp3 >> 3;
		adc1_sum_temp3 =  0;
	
		if(adc1_filter[2] >= DC_VOL_70*1.1)
		{
			TIM8_SET_COMPARE_CH3 -= 10;
			TIM1_SET_COMPARE_CH1 -= 10;
		}
	
		// AC BOOST
		if(adc1_filter[2] >= DC_VOL_65)
			TIM8_SET_COMPARE_CH3 -= 1;
		if(adc1_filter[2] <= DC_VOL_60)
			TIM8_SET_COMPARE_CH3 += 1;
		if(TIM8_SET_COMPARE_CH3 >= 600)
		{
			TIM8_SET_COMPARE_CH3 = 600;
		}
		if(TIM8_SET_COMPARE_CH3 <= 10)
		{
			TIM8_SET_COMPARE_CH3 = 10;
		}
		__HAL_TIM_SET_COMPARE(&htim8, TIM_CHANNEL_3, TIM8_SET_COMPARE_CH3);
		
		// DC BOOST
		if(adc1_filter[2] >= DC_VOL_55)
			TIM1_SET_COMPARE_CH1 -= 1;
		if(adc1_filter[2] <= DC_VOL_50)
			TIM1_SET_COMPARE_CH1 += 1;
		if(TIM1_SET_COMPARE_CH1 >= 900)
		{
			TIM1_SET_COMPARE_CH1 = 900;
		}
		if(TIM1_SET_COMPARE_CH1 <= 10)
		{
			TIM1_SET_COMPARE_CH1 = 10;
		}
		__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, TIM1_SET_COMPARE_CH1);
		
		// AC VOL OUTPUT
		OMEGA += 1;
		OMEGA = (OMEGA >= 1000) ? 0 : OMEGA;
		hspwm_omega = 2*PI*OMEGA / 1000;		
		
		rms_temp += (adc1_filter[1] - AC_VOL_AVG) * (adc1_filter[1] - AC_VOL_AVG) / 100.f;
		if (OMEGA % 250 == 0)
		{
			rms = 0.1*rms_temp + 0.9*rms;
			rms_temp = 0;
			
			if(rms <= RMS_SET)
				rms_co += 0.005;
			else
				rms_co -= 0.005;
			
			if(adc1_filter[2] <= DC_VOL_40)
				rms_co -= 0.02;
			
			rms_co = rms_co >= 1.5 ? 1.5 : rms_co;
			rms_co = rms_co <= 0.2 ? 0.2 : rms_co;
		}
		
//		if(rms_co >= 1.0)
//			TIM1_SET_COMPARE_CH2 = rms_co*(PERIOD_MAX_TIM1/2)*(arm_sin_f32(hspwm_omega) + k_co*(rms_co-1.0) * arm_sin_f32(3*hspwm_omega)) + PERIOD_MAX_TIM1/2 ;
//		else
			TIM1_SET_COMPARE_CH2 = rms_co*(PERIOD_MAX_TIM1/2)*arm_sin_f32(hspwm_omega)+ PERIOD_MAX_TIM1/2 ;

//		TIM1_SET_COMPARE_CH2 = 0.5*(PERIOD_MAX_TIM1/2)*arm_sin_f32(hspwm_omega) + PERIOD_MAX_TIM1/2 ;
		
		//PR1_OUT_P = (float)0.7 * (AC_VOL_SET * arm_sin_f32(hspwm_omega) - 2048 + adc1_filter[1]);
		//TIM1_SET_COMPARE_CH2 =  (PERIOD_MAX_TIM1 >> 1) + PR1_OUT_P + PR1_OUT_R;
		
		if(TIM1_SET_COMPARE_CH2 > PERIOD_MAX_TIM1 - 10)
		{
			TIM1_SET_COMPARE_CH2 = PERIOD_MAX_TIM1 - 10;
		}
		if(TIM1_SET_COMPARE_CH2 < 10)
		{
			TIM1_SET_COMPARE_CH2 = 10;
		}
		__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, TIM1_SET_COMPARE_CH2);
		__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, TIM1_SET_COMPARE_CH2);
		
	}
	
	/* TIM12 10kHz -------------------------------------------------------------- -------------------------------------------------------------- TIM12 10kHz*/
	if(htim->Instance == htim5.Instance)
	{		
		static int16_t TIM1_SET_COMPARE_CH1;
		
		static float temp;
		
		/* ADC2 Average */
		ADC2_Average(adc2_values);
		temp = 0.99f*temp + 0.01f*adc2_filter[0];
		RMS_SET = 1410000  + (temp - 2048) * 10;
		
//		HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, (AC_VOL_SET * arm_sin_f32(hspwm_omega) - 2048 + adc1_filter[1]) + 2048);
		
//		TIM1_SET_COMPARE_CH1 = adc2_filter[0] / 2;
//		TIM1_SET_COMPARE_CH1 = ( TIM1_SET_COMPARE_CH1 <= PERIOD_MAX_TIM1) ? TIM1_SET_COMPARE_CH1 : PERIOD_MAX_TIM1;
//		__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, TIM1_SET_COMPARE_CH1);
		
	}
	
	/* TIM9 2kHz -------------------------------------------------------------- -------------------------------------------------------------- TIM9 2kHz */
	if(htim->Instance == htim9.Instance)
	{
		//PR1_OUT_R = PR_Calculate(AC_VOL_SET - 2048 + adc1_filter[1], &hpr1);// + PR_Calculate(AC_Current_set-(int16_t)AC_CURRENT_CH1 + AC_CURRENT_CH1_AVG, &hpr3x1);
	}
	
	/* TIM12 10Hz -------------------------------------------------------------- -------------------------------------------------------------- TIM12 10Hz */
	if(htim->Instance == htim12.Instance)
	{
	}
}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

